using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace Framework
{
    [Serializable]
    public class AnimationData
    {
        public string Name;
        public int Width;
        public int height;
        //总帧数
        public int FrameCount;
        //总时长
        public float Length;
        public int PixelOffset;
        public float Scale;
        public AnimationState State { get; set; }
        public AnimationData()
        {
            Scale = 1f;
        }

        public int GetPixelId(int vertexId, float t)
        {
            return PixelOffset + vertexId * FrameCount + Mathf.FloorToInt(FrameCount * Mathf.Clamp01(t));
        }
        public Vector2 GetUv(int vertexId, float t)
        {
            var id = GetPixelId(vertexId, t);
            float w = this.Width;
            return new Vector2((id % Width) / w, (id / Width) / w);
        }
    }
    public partial class TextureAnimation : MonoBehaviour
    {
        public int VertexCount;
        public Mesh Mesh;
        public List<AnimationData> Animations;
        private void Start()
        {
            if (Animations == null || Animations.Count < 1)
            {
                return;
            }
            var meshfilter = this.GetComponent<MeshFilter>();
            if (meshfilter == null)
            {
                meshfilter = this.gameObject.AddComponent<MeshFilter>();

            }
            meshfilter.mesh = this.Mesh;
            var renderer = this.GetComponent<MeshRenderer>();
            if (renderer == null)
            {
                renderer = this.gameObject.AddComponent<MeshRenderer>();
            }
        }

        public void Play(string name)
        {

        }
        public void Stop()
        {

        }
    }
    public partial class TextureAnimation
    {
#if UNITY_EDITOR
        [ContextMenu("生成")]
        private void Run()
        {
            Animations = new List<AnimationData>();
            var ani = this.GetComponent<Animation>();
            if (ani == null)
            {
                return;
            }
            var skin = this.GetComponentInChildren<SkinnedMeshRenderer>(true);
            if (skin == null)
            {
                return;
            }
            skin.gameObject.SetActive(false);
            this.Mesh = skin.sharedMesh;
            var vertexCount = skin.sharedMesh.vertexCount;
            this.VertexCount = vertexCount;
            var totalFrameCount = 0;
            List<AnimationState> states = new List<AnimationState>();
            var e = ani.GetEnumerator();
            while (e.MoveNext())
            {
                if (e.Current is AnimationState state)
                {
                    states.Add(state);
                }
            }
            if (states.Count < ani.GetClipCount())
            {
                Debug.LogError("change clip to legacy mode");
                return;
            }
            var list = new List<AnimationData>();
            int dataOffset = 0;
            foreach (var state in states)
            {
                var frame = Mathf.FloorToInt(state.clip.frameRate * state.clip.length);
                var data = new AnimationData();
                data.State = state;
                data.Name = state.name;
                data.FrameCount = frame;
                data.Length = state.clip.length;
                data.PixelOffset = dataOffset;
                list.Add(data);
                totalFrameCount += frame;
                dataOffset += frame * vertexCount;
                Animations.Add(data);

            }
            Debug.LogError("vertex:" + vertexCount);
            Debug.LogError("frames:" + totalFrameCount);
            var pixelCount = totalFrameCount * vertexCount;
            Debug.LogError("pixels:" + pixelCount);
            int width = Mathf.NextPowerOfTwo(Mathf.CeilToInt(Mathf.Sqrt(pixelCount)));
            int height = Mathf.NextPowerOfTwo(pixelCount / width + 1);
            // size = 1024;
            Debug.LogErrorFormat("size:{0},{1}", width, height);
            var path = Utils.Unity.GetAssetPath(gameObject);
            if (string.IsNullOrEmpty(path))
            {
                Debug.LogError("not find path");
                return;
            }
            path = Path.Combine(Path.GetDirectoryName(path), "aniTex.png");
            Debug.LogError(path);
            // return;
            var compressValue = false;
            var len = list.Count;
            var pixels = new Color[pixelCount];
            for (int i = 0; i < len; i++)
            {
                var data = list[i];
                data.Width = width;
                data.height = height;
                var state = data.State;
                ani.clip = state.clip;
                var frame = data.FrameCount;
                var deltaTime = data.Length / frame;
                var offset = data.PixelOffset;
                var time = 0f;
                var mesh = new Mesh();
                float minValue = float.MaxValue;
                float maxValue = float.MinValue;

                for (int f = 0; f < frame; f++)
                {
                    state.time = time;
                    ani.Sample();
                    time += deltaTime;
                    skin.BakeMesh(mesh);

                    for (int v = 0; v < vertexCount; v++)
                    {
                        var id = offset + v * frame + f;
                        var pos = mesh.vertices[v];
                        pixels[id] = new Color(pos.x, pos.y, pos.z, 1f);
                        if (compressValue)
                        {
                            minValue = Mathf.Min(pos.x, minValue); maxValue = Mathf.Max(pos.x, maxValue);
                            minValue = Mathf.Min(pos.y, minValue); maxValue = Mathf.Max(pos.y, maxValue);
                            minValue = Mathf.Min(pos.z, minValue); maxValue = Mathf.Max(pos.z, maxValue);
                        }
                    }
                }
                // Debug.LogErrorFormat("name:{0},frame:{1},min:{2},max:{3}", data.Name, frame, minValue, maxValue);
                if (compressValue)
                {
                    var dis = maxValue - minValue;
                    var scale = 1f;
                    if (dis > 0)
                    {
                        scale = 1f / dis;
                        data.Scale = scale;
                    }
                    for (int f = 0; f < frame; f++)
                    {
                        for (int v = 0; v < vertexCount; v++)
                        {
                            var id = offset + v * frame + f;
                            var c = pixels[id] * scale;
                            maxValue = float.MinValue;
                            maxValue = Mathf.Max(c.r, maxValue);
                            maxValue = Mathf.Max(c.g, maxValue);
                            maxValue = Mathf.Max(c.b, maxValue);
                            c.r /= maxValue;
                            c.g /= maxValue;
                            c.b /= maxValue;
                            c.r = c.r * 2f - 1f;
                            c.g = c.g * 2f - 1f;
                            c.b = c.b * 2f - 1f;
                            c.a = 1f / maxValue;
                            pixels[id] = c;
                        }
                    }
                }
            }
            var tex2d = new Texture2D(width, height, compressValue ? TextureFormat.RGBA32 : TextureFormat.RGBAHalf, false);
            for (int i = 0; i < pixelCount; i++)
            {
                var c = pixels[i];
                var px = i % width;
                var py = i / width;
                tex2d.SetPixel(px, py, c);
            }
            tex2d.Apply();
            File.WriteAllBytes(path, tex2d.EncodeToPNG());
            ani.clip = null;
            Debug.LogError("完成");

        }
#endif
    }


}